/*
 * Project: Generic Project Controls
 * Package: net.made2ordersoftware.control
 * File:    AbstractService
 * Created: Aug 18, 2012
 */

/*
 *  Copyright 2010 Made 2 Order Software, LLC
 *
 *  All rights reserved. No part of this software may be reproduced, stored in a retrieval system, or
 *  transmitted in any form or by any means, without the prior written permission of Made 2 Order Software.
 *
 *  You may not distribute the URL or redistribute the files to third parties. You may transfer the files
 *  onto a single storage device so long as you can prove ownership of the software. You may not reverse
 *  engineer, decompile, or disassemble the software or media files. You may not modify or translate the
 *  software or media, or distribute copies of the software or media without the written consent of Made
 *  2 Order Software
 */
package com.made2ordersoftware.service;

import java.util.List;
import javax.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Abstract service class for generic CRUD operations.
 *
 * @param <T>
 * @author David Canning
 * @version 1.0
 */
public abstract class AbstractService<T> {

   protected static final Logger LOG = LoggerFactory.getLogger(AbstractService.class);
   private Class<T> entityClass;

   /**
    * Creates a
    * <code>AbstractService</code> entity.
    *
    * @param entityClass
    */
   public AbstractService(Class<T> entityClass) {
      this.entityClass = entityClass;
   }

   /**
    * Returns the current
    * <code>EntityManager</code> for this session.
    *
    * @return
    */
   protected abstract EntityManager getEntityManager();

   /**
    * Persists a newly created object of type
    * <code>T</code>.
    *
    * @param entity
    */
   public void create(T entity) {
      getEntityManager().persist(entity);
   }

   /**
    * Persists the changes of type
    * <code>T</code>.
    *
    * @param entity
    */
   public void edit(T entity) {
      getEntityManager().merge(entity);
   }

   /**
    * Removes object of type
    * <code>T</code> from the database.
    *
    * @param entity
    */
   public void remove(T entity) {
      getEntityManager().remove(getEntityManager().merge(entity));
   }

   /**
    * Returns object of type
    * <code>T</code> by id.
    *
    * @param id
    * @return
    */
   public T find(Object id) {
      return getEntityManager().find(entityClass, id);
   }

   /**
    * Returns all object of type
    * <code>T</code>.
    *
    * @return
    */
   public List<T> findAll() {
      javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().
            createQuery();
      cq.select(cq.from(entityClass));
      return getEntityManager().createQuery(cq).getResultList();
   }

   /**
    * Returns object of type
    * <code>T</code> by id range.
    *
    * @param range
    * @return
    */
   public List<T> findRange(int[] range) {
      javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().
            createQuery();
      cq.select(cq.from(entityClass));
      javax.persistence.Query q = getEntityManager().createQuery(cq);
      q.setMaxResults(range[1] - range[0]);
      q.setFirstResult(range[0]);
      return q.getResultList();
   }

   /**
    * Returns count of records for object of type
    * <code>T</code> in database.
    *
    * @return
    */
   public int count() {
      javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().
            createQuery();
      javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
      cq.select(getEntityManager().getCriteriaBuilder().count(rt));
      javax.persistence.Query q = getEntityManager().createQuery(cq);
      return ((Long) q.getSingleResult()).intValue();
   }
}
